import cn from 'classnames';

import React from 'react';
import PropTypes from 'prop-types';
import { Link } from 'react-router-dom';

import { gql, useQuery, useMutation } from '@apollo/client';

import { Error } from '@kuiper/react-base';
import notification from '@kuiper-components/notification';
import EmptyData from '../../../components/empty/EmptyData';
import Pagination from '@knownsec/react-component/dist/Pagination';
import { searchStringBuilder } from '@kuiper-components/page-table';
import Table from '@knownsec/react-component/dist/Table';
import Button from '@kuiper-components/button';
import Tooltip from '@kuiper-components/tooltip';

import { datetime } from '../../../../common/formatter';
import {
	WARN_LEVEL_MAP,
	TASK_KEY_LABEL_MAP,
	SSL_CATEGORY_KEY_LABEL_MAP,
} from '../../../../common/constants';
import WarningsStatusEdit from '../../../components/WarningsStatusEdit';
import Breadcrumb, { Item } from '../../../components/Breadcrumb';
import DetailHead from '../../../components/DetailHead';
import Label from '../../../components/Label';
import CopyBoard from '../../../components/CopyBoard';
import TableToolbox from './TableToolbox';
import NewSuggest from './NewSuggest';
import s from './style.module.css';
import collectType from '../../../../common/collectType';
import { getParams } from '../../../helpers/getUrlParams';

const TASK = gql`
	query($taskId: MongoID!) {
		task: TaskOne(filter: { _id: $taskId }) {
			_id
			job {
				_id
				note
				cydEnabled
			}
			target
			endTime
			taskType
			triggerType
			isLatestTask
			result {
				warnings {
					_id
					id
					level
					title
					affects
					detail
					category
					recommendation
					description
					detailText
					reference
					ignoredTime
					isResolved
				}
			}
			taskSettings {
				collect
			}
		}
	}
`;
const IGORE_WARN = gql`
	mutation($taskId: MongoID!, $warnIds: [String]!) {
		ignoreWarn(taskId: $taskId, warnIds: $warnIds) {
			_id
			result {
				warnings {
					_id
					id
					level
					title
					detail
					ignoredTime
				}
			}
		}
	}
`;
const UNIGORE_WARN = gql`
	mutation($taskId: MongoID!, $warnIds: [String]!) {
		unignoreWarn(taskId: $taskId, warnIds: $warnIds) {
			_id
			result {
				warnings {
					_id
					id
					level
					title
					affects
					detail
					category
					ignoredTime
				}
			}
		}
	}
`;
const findFilterObj = () => {
	const idx = location.href.indexOf('filter');
	let o = null;
	if (idx > -1) {
		const str = location.href.substr(location.href.indexOf('?') + 1);
		const param = new URLSearchParams(str);
		o = JSON.parse(param.get('filter') || '{}');
	} else {
		o = {};
	}
	return o;
};

function warningStatsBuilder(warning = {}, modifiedAble = true) {
	let text;
	if (warning.ignoredTime) {
		text = (
			<Tooltip
				placement="top"
				overlay={
					<span className={s.time}>
						忽略操作: {datetime(warning.ignoredTime)}
					</span>
				}
			>
				<span className={s.ignored}>已忽略</span>
			</Tooltip>
		);
	} else if (warning.isResolved) {
		text = <span className={s.resolved}>已修复</span>;
	} else {
		text = <span className={s.notResolved}>待修复</span>;
	}
	return text;
}
function WarningDetail({
	className,
	location,
	history,
	match: {
		params: { taskId },
	},
}) {
	// const [selectedRows, setRowSelect] = React.useState({});
	const params = getParams();
	const fil = findFilterObj();
	const [colum, setColum] = React.useState([]);
	const [tp, setTp] = React.useState('empty');
	const [selectedRowKeys, setSelectedRowKeys] = React.useState([]);

	const onSelectChange = newSelectedRowKeys => {
		setSelectedRowKeys(newSelectedRowKeys);
	};

	const rowSelection = {
		selectedRowKeys,
		onChange: onSelectChange,
	};
	const { loading, error, data } = useQuery(TASK, {
		variables: { taskId },
	});

	React.useEffect(() => {
		if (data) {
			setTp('img');
		}
	}, [data]);

	const [updateIgnoreWarn] = useMutation(IGORE_WARN);
	const [updateUnignoreWarn] = useMutation(UNIGORE_WARN);
	const { tableData, total } = React.useMemo(() => {
		const datas =
			data?.task?.result?.warnings?.map(row => ({
				...row,
				_id: row?.id,
				warningId: row._id,
				key: row,
				status: row.isResolved
					? 'resolved'
					: row.ignoredTime
					? 'ignored'
					: 'unresolved',
			})) || [];
		const page = params?.page || 1;
		const pageSize = params?.pageSize || 10;
		let arr = [];
		const filterArr = Object.entries(fil);
		arr = datas.filter(row => {
			return filterArr.every(([field, value]) => {
				if (field === 'targetSearch') {
					return row.affects === value;
				} else {
					return row[field] == value;
				}
			});
		}).sort((a, b) => { return b.level - a.level }); // 按漏洞等级倒序排序
		const total = arr.length;
		const arrs = arr.slice((page - 1) * pageSize, page * pageSize);
		return { tableData: arrs, total: total };
	}, [data, fil, params]);

	if (error) {
		return <Error error={error} />;
	}

	let endTime = data?.task?.endTime;
	endTime = endTime ? datetime(new Date(endTime)) : '';
	const {
		target,
		taskType,
		triggerType,
		taskSettings: { collect },
		isLatestTask,
		job,
	} = data?.task || { taskSettings: {} };

	const routePrefix = `/weakness/${taskType}/detail/${taskId}`;

	const handleFilterChange = filter => {
		const search = searchStringBuilder(location.search, {
			filter: JSON.stringify(filter),
			page: 1,
			pageSize: 10,
			sort: '_ID_DESC',
		});
		setSelectedRowKeys([]);
		history.push(`${routePrefix}?${search}`);
	};

	const pageChange = (page, pageSize) => {
		const search = searchStringBuilder(location.search, {
			filter: JSON.stringify(fil),
			page: page,
			pageSize: pageSize,
			sort: '_ID_DESC',
		});
		history.push(`${routePrefix}?${search}`);
	};

	const handleIgnoreWarn = ingoreWarnIds => {
		return updateIgnoreWarn({
			variables: {
				taskId,
				warnIds: [].concat(ingoreWarnIds),
			},
		})
			.then(() => {
				// setRowSelect({});
				setSelectedRowKeys([]);
				notification.success({
					placement: 'top',
					message: '忽略告警成功',
				});
			})
			.catch(error =>
				notification.error({
					message: '忽略告警失败',
					description: error.message,
					placement: 'top',
				})
			);
	};
	const handleUnignoreWarn = uningoreWarnIds => {
		return updateUnignoreWarn({
			variables: {
				taskId,
				warnIds: [].concat(uningoreWarnIds),
			},
		})
			.then(() => {
				setSelectedRowKeys([]);
				notification.success({
					placement: 'top',
					message: '取消忽略告警成功',
				});
			})
			.catch(error =>
				notification.error({
					message: '取消忽略告警失败',
					description: error.message,
					placement: 'top',
				})
			);
	};

	const columns = [
		{
			title: '风险地址',
			dataIndex: 'affects',
			key: 'affects',
			// eslint-disable-next-line
			render(affects) {
				return <CopyBoard text={affects} maxWidth="12rem" />;
			},
		},
		{
			title: `${taskType === 'ssl' ? '威胁' : '漏洞'}名称`,
			dataIndex: 'title',
			key: 'title',
			render(title) {
				return (
					<div className={cn(s.titl, s.ell)} title={title}>
						{title}
					</div>
				);
			},
		},
		{
			title: taskType === 'ssl' ? '威胁等级' : '漏洞等级',
			dataIndex: 'level',
			key: 'level',
			width: 100,
			render(status, record) {
				const color = ['#FAAF2C', '#F3665C', '#F04038'];
				return (
					<span style={{ color: color[status - 1] }}>
						{WARN_LEVEL_MAP[status]}
					</span>
				);
			},
		},
		{
			title: taskType === 'ssl' ? '威胁状态' : '漏洞状态',
			dataIndex: 'status',
			key: 'status',
			width: 100,
			render(status, record) {
				return (
					<div>
						{warningStatsBuilder(record, isLatestTask)}
						{isLatestTask && (
							<WarningsStatusEdit
								taskId={data?.task?._id}
								idsObj={{ [record?.id]: true }}
							/>
						)}
					</div>
				);
			},
		},
		{
			title: '操作',
			dataIndex: 'id',
			key: 'suggest',
			width: 100,
			// eslint-disable-next-line
			render: (
				id,
				{
					warningId,
					title,
					status,
					impact,
					recommendation,
					description,
					reference,
					category,
				}
			) => {
				if (data) return (
				<NewSuggest
					key={id + Math.random().toString(36).slice(-6)}
					className={s.linkBtn}
					title={title}
					status={status}
					isLatestTask={isLatestTask}
					taskId={data?.task?._id}
					warningId={warningId}
					taskType={taskType}
					impact={impact}
					category={category}
					reference={reference}
					recommendation={recommendation}
					description={description}
					cydEnabled={data?.task?.job?.cydEnabled}
					onSetIgnore={() => handleIgnoreWarn(id)}
					onSetUnignore={() => handleUnignoreWarn(id)}
				>
					查看详情
				</NewSuggest>
			)},
		},
	];
	React.useEffect(() => {
		const sslObj = {
			title: '威胁类型',
			dataIndex: 'category',
			key: 'category',
			width: 100,
			render: cate => SSL_CATEGORY_KEY_LABEL_MAP[cate],
		};
		const vulObj = {
			title: '漏洞类型',
			dataIndex: 'category',
			key: 'category',
			width: 100,
		};
		if (taskType === 'ssl') {
			const idx = columns.findIndex(item => item.key === 'level');
			columns.splice(idx + 1, 0, sslObj);
		}
		if (taskType === 'vul') {
			const idx = columns.findIndex(item => item.key === 'level');
			columns.splice(idx + 1, 0, vulObj);
		}
		setColum(columns);
	}, [taskType]);
	return (
		<div className={cn(className, s.warningDetail)}>
			<div className={s.breadcrumb}>
				<Breadcrumb>
					<Item disabled key="weakness">
						脆弱性监测
					</Item>
					<Item
						key={`${taskType}/overview${taskType === 'vul' ? '/normal' : ''}`}
					>
						{TASK_KEY_LABEL_MAP[taskType]}监测
					</Item>
					{location?.state?.refer && <Item>
						<Link className={s.breadItem} to={`/weakness/${taskType}/history/${location?.state?.jobId}?` + location?.state?.refer}>历史任务</Link>
					</Item>}
					<Item>监测详情</Item>
				</Breadcrumb>
			</div>
			<main className={s.container}>
				<div className={s.header}>
					<div className={s.row}>
						<Label>监测任务信息</Label>
					</div>
					<DetailHead taskId={taskId} type={taskType} />
				</div>
				<div className={s.header}>
					<Label>{TASK_KEY_LABEL_MAP[taskType]}监测详情</Label>
				</div>

				<TableToolbox onChange={handleFilterChange} taskType={taskType} />
				{isLatestTask ? (
					<>
						<Table
							loading={loading}
							className={s.newtable}
							pro
							columns={colum}
							data={tableData}
							rowSelection={rowSelection}
							empty={<EmptyData className={s.nobor} />}
						/>
						<div>
							<WarningsStatusEdit
								className={s.batchBtn}
								taskId={data?.task?._id}
								isBatchSetting={true}
								afterActionSuccessful={() => setSelectedRowKeys([])}
								idsObj={selectedRowKeys.reduce((cur, item) => {
									cur[item.id] = item;
									return cur;
								}, {})}
							/>
							<div className={cn(s.df)}>
								{total > 10 && (
									<Pagination
										total={total}
										current={params?.page || 1}
										pageSize={params?.pageSize || 10}
										pageSizeOptions={[10, 20, 50]}
										showSizeChanger
										showQuickJumper
										showTotal={total => `共${total}条`}
										onChange={pageChange}
									/>
								)}
							</div>
						</div>
					</>
				) : (
					<>
						<Table
							key={taskId + Math.random().toString(36).slice(-6)}
							loading={loading}
							className={s.newtable}
							pro
							columns={colum}
							data={tableData}
							empty={<EmptyData className={s.nobor} type={tp} />}
						/>
						<div className={cn(cn(s.df, s.mt1rem))}>
							{total > 10 && (
								<Pagination
									total={total}
									current={params?.page || 1}
									pageSize={params?.pageSize || 10}
									pageSizeOptions={[10, 20, 50]}
									showSizeChanger
									showQuickJumper
									showTotal={total => `共${total}条`}
									onChange={pageChange}
								/>
							)}
						</div>
					</>
				)}
			</main>
		</div>
	);
}

WarningDetail.propTypes = {
	className: PropTypes.string,
	match: PropTypes.shape({
		params: PropTypes.shape({
			taskId: PropTypes.string.isRequired,
		}).isRequired,
	}).isRequired,
	location: PropTypes.shape({
		search: PropTypes.string.isRequired,
		state: PropTypes.shape({
			prevPath: PropTypes.string,
		}),
	}).isRequired,
	history: PropTypes.shape({
		push: PropTypes.func.isRequired,
	}).isRequired,
};
WarningDetail.defaultProps = {
	className: s.WarningDetail,
};

export default WarningDetail;
